package edu.stanford.bmir.protege.web.server.transform.service;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationSubject;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataHasValue;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;

import edu.stanford.bmir.protege.web.server.IdUtil;
import edu.stanford.bmir.protege.web.server.filesubmission.FileUploadConstants;
import edu.stanford.bmir.protege.web.shared.transform.MappingBean;

public abstract class OwlUtil {

	private final File uploadsDirectory = FileUploadConstants.UPLOADS_DIRECTORY;

	public OWLOntologyManager manager = OWLManager.createOWLOntologyManager();

	public OWLDataFactory factory = manager.getOWLDataFactory();

	public OWLOntology ontology = null;

	public Map<String, String> pros = null;

	public Set<OWLAxiom> sets = new HashSet<OWLAxiom>();

	public Map<String, IRI> iris = new HashMap<String, IRI>();

	private String path;

	public OwlUtil(String path, Map<String, String> pros, IRI projectIRI)
			throws Exception {
		this.path = path;
		ontology = manager.createOntology(projectIRI);
		this.pros = pros;
	}

	public String getOwlPath() {
		// 创建属性
		createProperty();
		// 创建类
		createClasses();

		return print();
	}

	private String print() {

		manager.addAxioms(ontology, sets);

		String name = "uploads-" + new Date().getTime() + ".owl";

		String filePath = uploadsDirectory.getAbsolutePath() + File.separator
				+ name;

		File file = new File(filePath);

		try {
			manager.saveOntology(ontology, IRI.create(file));
		} catch (OWLOntologyStorageException e) {
			e.printStackTrace();
		}
		return name;
	}

	public List<MappingBean> getProperties() {

		List<MappingBean> mblst = new ArrayList<MappingBean>();

		List<String> lst = getProperty(path);

		for (String str : lst) {

			MappingBean bean = new MappingBean();
			bean.setName(str);
			bean.setMapping("");

			mblst.add(bean);

		}

		return mblst;
	}

	private void createProperty() {
		Set set = pros.keySet();
		Iterator iter = set.iterator();
		while (iter.hasNext()) {
			String key = (String) iter.next();
			String value = pros.get(key);
			createProperty(key, value);
		}
	}

	protected abstract void createProperty(String key, String value);

	protected abstract List<String> getProperty(String path);

	protected abstract void createClasses();

	/**
	 * 创建数据属性
	 * 
	 * @param name
	 */
	protected void createDataproperty(String name) {

		OWLDataProperty odp = factory.getOWLDataProperty(createIRI(name));
		OWLDataProperty podp = factory.getOWLDataProperty(IRI
				.create(StringWord.TOPDATAPROPERTY));
		OWLAxiom ax = factory.getOWLSubDataPropertyOfAxiom(odp, podp);

		OWLAxiom axiom = factory.getOWLAnnotationAssertionAxiom(odp
				.asOWLDataProperty().getIRI(), getLabel(name));
		sets.add(axiom);

		sets.add(ax);
	}

	protected OWLObjectProperty createObjectproperty(String name,
			OWLClass dCls, OWLClass rCls) {

		OWLObjectProperty odp = factory.getOWLObjectProperty(createIRI(name));
		OWLObjectProperty podp = factory.getOWLObjectProperty(IRI
				.create(StringWord.TOPOBJECTPROPERTY));

		OWLAxiom ax = factory.getOWLSubObjectPropertyOfAxiom(odp, podp);

		OWLAxiom axiom = factory.getOWLAnnotationAssertionAxiom(odp
				.asOWLObjectProperty().getIRI(), getLabel(name));
		sets.add(axiom);

		OWLObjectPropertyDomainAxiom daxiom = factory
				.getOWLObjectPropertyDomainAxiom(odp, dCls);
		OWLObjectPropertyRangeAxiom raxiom = factory
				.getOWLObjectPropertyRangeAxiom(odp, rCls);

		sets.add(daxiom);
		sets.add(raxiom);

		sets.add(ax);

		return odp;

	}

	/**
	 * 添加对象属性
	 */
	protected void addObjectproperty(OWLObjectProperty odp, String value,
			OWLClass cls) {

		OWLClass nose = factory.getOWLClass(createIRI(value));

		setLabel(nose.asOWLClass().getIRI(), value);

		OWLClassExpression hasPartSomeNose = factory
				.getOWLObjectSomeValuesFrom(odp, nose);

		OWLSubClassOfAxiom ax = factory.getOWLSubClassOfAxiom(cls,
				hasPartSomeNose);

		sets.add(ax);

	}

	/**
	 * 添加数据属性
	 */
	protected void addDataproperty(String name, String value, OWLClass cls) {

		OWLLiteral oli = factory.getOWLLiteral(value);
		OWLDataProperty owp = factory.getOWLDataProperty(createIRI(name));

		OWLDataHasValue hasValue = factory.getOWLDataHasValue(owp, oli);

		OWLSubClassOfAxiom ax = factory.getOWLSubClassOfAxiom(cls, hasValue);

		sets.add(ax);

	}

	/**
	 * 添加对象属性
	 */
	protected void addObjectproperty(String name, String value, OWLClass cls) {

		OWLObjectProperty hasPart = factory
				.getOWLObjectProperty(createIRI(name));

		OWLClass nose = factory.getOWLClass(createIRI(value));

		setLabel(nose.asOWLClass().getIRI(), value);

		OWLClassExpression hasPartSomeNose = factory
				.getOWLObjectSomeValuesFrom(hasPart, nose);

		OWLSubClassOfAxiom ax = factory.getOWLSubClassOfAxiom(cls,
				hasPartSomeNose);

		sets.add(ax);

	}

	/**
	 * 设置等价类
	 */
	public void addEquivalentClass(OWLClass clsA, String eName) {

		OWLClass clsB = factory.getOWLClass(createIRI(eName));

		setLabel(clsB.asOWLClass().getIRI(), eName);

		OWLEquivalentClassesAxiom classExpressions = factory
				.getOWLEquivalentClassesAxiom(clsA, clsB);

		sets.add(classExpressions);

	}

	/**
	 * 获取label
	 * 
	 * @param name
	 * @return
	 */
	protected OWLAnnotation getLabel(String name) {
		OWLLiteral lbl = factory.getOWLLiteral(name);
		OWLAnnotation label = factory.getOWLAnnotation(
				factory.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_LABEL
						.getIRI()), lbl);
		return label;
	}

	/**
	 * 创建对象属性
	 * 
	 * @param name
	 */
	protected void createObjectproperty(String name) {

		OWLObjectProperty odp = factory.getOWLObjectProperty(createIRI(name));
		OWLObjectProperty podp = factory.getOWLObjectProperty(IRI
				.create(StringWord.TOPOBJECTPROPERTY));
		OWLAxiom ax = factory.getOWLSubObjectPropertyOfAxiom(odp, podp);

		OWLAxiom axiom = factory.getOWLAnnotationAssertionAxiom(odp
				.asOWLObjectProperty().getIRI(), getLabel(name));
		sets.add(axiom);

		sets.add(ax);

	}

	/**
	 * 获取类thing
	 */
	protected OWLClass getRootClass() {
		return factory.getOWLThing();
	}

	protected IRI createIRI(String name) {

		IRI iri = iris.get(name);
		if (iri == null) {
			iri = createIRI(StringWord.BASEURL, ontology, name,true);
			try {
				URI create = URI.create(iri.toString());
			} catch (Exception e) {
				iri = createIRI(StringWord.BASEURL, ontology, name,false);
			}
			iris.put(name, iri);
		}
		return iri;
	}

	protected static final String START_CHAR = "R";

	protected static IRI createIRI(String base, OWLOntology ontology,
			String name, boolean selfDefine) {
		if (selfDefine) {
			// 根据客户需求修改IRI 将IRI进行自定义
			name = name.replaceAll(" ", "_");// 对于含空格的词将空格变为下划线进行
			return IRI.create(base + name);
		}
		if (!selfDefine) {
			while (true) {
				String base62Fragment = IdUtil.getBase62UUID();
				StringBuilder sb = new StringBuilder();
				sb.append(base);
				sb.append(START_CHAR);
				sb.append(base62Fragment);
				IRI iri = IRI.create(sb.toString());
				if (!ontology.containsEntityInSignature(iri)) {
					return iri;
				}
			}
		}
		return null;
	}

	public OWLClass createClass(String name, String pName) {

		OWLClass cls = factory.getOWLClass(createIRI(name));

		OWLClass pCls = getRootClass();

		if (pName != null && pName != "" && pName != "null") {
			pCls = factory.getOWLClass(createIRI(pName));
		}

		OWLSubClassOfAxiom axiom = factory.getOWLSubClassOfAxiom(cls, pCls);

		sets.add(axiom);

		OWLAxiom axiom1 = factory.getOWLAnnotationAssertionAxiom(cls
				.asOWLClass().getIRI(), getLabel(name));
		sets.add(axiom1);

		return cls;

	}

	protected void setLabel(OWLAnnotationSubject subject, String name) {
		OWLAxiom axiom1 = factory.getOWLAnnotationAssertionAxiom(subject,
				getLabel(name));
		sets.add(axiom1);
	}

	protected List<String> getProName(String value) {

		List<String> ps = new ArrayList<String>();

		Set set = pros.keySet();
		Iterator iter = set.iterator();
		while (iter.hasNext()) {
			String k = (String) iter.next();
			String v = pros.get(k);

			if (value.equals(v)) {
				ps.add(k);
			}

		}
		return ps;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

}
